/* common.c
**    Authors: 
**      sejishikong <sejishikong@263.net>
**      Wei Lian <lianwei2003.student@sina.com> (rewrited the code based on first author's work, added the support for sound volumn control, the support for terminating player, and the support for player arguments. rearranged the section dealing with status show)
**
**    This program is free software; you can redistribute it and/or modify
**    it under the terms of the GNU General Public License Version 2 as
**    published by the Free Software Foundation;
**
**    This program is distributed in the hope that it will be useful,
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**    GNU General Public License for more details.
**
**    You should have received a copy of the GNU General Public License
**    along with this program; if not, write to the Free Software
**    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
*/

#include <sys/soundcard.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <qapplication.h>
#include <qtabwidget.h>
#include <qvbox.h>
#include <qhbox.h>
#include <qlistview.h>
#include <qlabel.h>
#include <qslider.h>
#include <qpushbutton.h>
#include <qlineedit.h>
#include <qhttp.h>
#include <qbuffer.h>
#include <qregexp.h>
#include <qprocess.h>
#include <qstatusbar.h>
#include <qtimer.h>
#include <qsettings.h>

class Sopcast:public QTabWidget
{
Q_OBJECT public:
    Sopcast (QWidget * parent = 0, const char *name = 0);
private:
  int sound_read ();
  QListView *listchannel;
  QBuffer *buffer;
  QProcess *sop;
  QProcess *player;
  QStatusBar *statusbar;
  QHttp *http;
  QLineEdit *editplayer;
  QLineEdit *editchannelurl;
  QLineEdit *editchannelheader;
  int sound_handle;
  void killsop ();
  void killplayer ();
  void forkplayer ();
  void forksop ();
  QString channelname;
  QPushButton *buttonchannel;
  bool fetchingchannel;

  private slots:void httpdone (bool);
  void fetchchannel ();
  void onbuttonplayerclicked ();
  void onbuttonstopclicked ();
  void onbuttonquitclicked ();
  void onbuttonrecordclicked ();
  void onbuttonsaveclicked ();
  void parsestdout ();
  void sound_write (int);
  void onlistitemclicked ();

};


Sopcast::Sopcast (QWidget * parent, const char *name):
QTabWidget (parent, name)
{
////tab1
  QVBox *tab = new QVBox (this);
  listchannel = new QListView (tab);
  listchannel->addColumn (tr ("Channel"));
  listchannel->addColumn (tr ("Type"));
  listchannel->addColumn (tr ("Kbps"));
  listchannel->addColumn (tr ("Users"));
  listchannel->addColumn (tr ("QualityC"));
  listchannel->addColumn (tr ("QualityS"));
  listchannel->addColumn (tr ("StarFrom"));
  listchannel->addColumn (tr ("URL"));

  QHBox *hbox = new QHBox (tab);
  buttonchannel = new QPushButton ("Channel", hbox);
  buttonchannel->setToggleButton (TRUE);
  QPushButton *buttonplayer = new QPushButton ("Player", hbox);
  QPushButton *buttonstop = new QPushButton ("Stop", hbox);

  if ((sound_handle = open ("/dev/mixer", O_RDWR, 0)) == -1)
    {
      perror ("/dev/mixer");
      return;
    }
  QSlider *slidersound =
    new QSlider (0, 100, 10, sound_read (), QSlider::Horizontal, hbox);

  QPushButton *buttonrecord = new QPushButton ("Record", hbox);

  statusbar = new QStatusBar (tab);

  addTab (tab, "Sopcast");
/////tab2
  tab = new QVBox (this);
  QSettings settings;

  hbox = new QHBox (tab);
  QLabel *label;
  label = new QLabel ("Player:", hbox);
  editplayer =
    new QLineEdit (settings.
		   readEntry ("/sopcast/player",
			      "mplayer -ontop -geometry 100%:100%"), hbox);

  hbox = new QHBox (tab);
  label = new QLabel ("Channels url:", hbox);
  editchannelurl =
    new QLineEdit (settings.
		   readEntry ("/sopcast/channelurl",
			      "http://www.sopcast.org/channel/index.php"),
		   hbox);

  hbox = new QHBox (tab);
  label = new QLabel ("Channels url header:", hbox);
  editchannelheader =
    new QLineEdit (settings.
		   readEntry ("/sopcast/channelheader",
			      "sop://broker.sopcast.org"), hbox);

  QPushButton *buttonsave = new QPushButton ("Save", tab);

  addTab (tab, "Config");
/////signal and slot  
  http = new QHttp ();
  connect (slidersound, SIGNAL (valueChanged (int)),
	   SLOT (sound_write (int)));
  connect (http, SIGNAL (done (bool)), SLOT (httpdone (bool)));
  connect (buttonchannel, SIGNAL (clicked ()), this, SLOT (fetchchannel ()));
  connect (buttonstop, SIGNAL (clicked ()), this,
	   SLOT (onbuttonstopclicked ()));
  connect (buttonplayer, SIGNAL (clicked ()), this,
	   SLOT (onbuttonplayerclicked ()));
  connect (buttonrecord, SIGNAL (clicked ()), this,
	   SLOT (onbuttonrecordclicked ()));
  connect (buttonsave, SIGNAL (clicked ()), this,
	   SLOT (onbuttonsaveclicked ()));
  connect (listchannel, SIGNAL (doubleClicked (QListViewItem *)), this,
	   SLOT (onlistitemclicked ()));
////initialization
  sop = NULL;
  player = NULL;
  fetchingchannel = FALSE;
  fetchchannel ();
}

void
Sopcast::onbuttonsaveclicked ()
{
  QSettings settings;
  settings.writeEntry ("/sopcast/player", editplayer->text ());
  settings.writeEntry ("/sopcast/channelurl", editchannelurl->text ());
  settings.writeEntry ("/sopcast/channelheader", editchannelheader->text ());
}

void
Sopcast::onbuttonrecordclicked ()
{

}

void
Sopcast::onlistitemclicked ()
{
  killsop ();
  killplayer ();
  channelname = listchannel->currentItem ()->text (0);
  forksop ();
  statusbar->message (tr ("Connecting..."));
}

void
Sopcast::forksop ()
{
  sop = new QProcess (this);
  sop->addArgument ("sp-sc");
  sop->addArgument (listchannel->currentItem ()->text (7));
  sop->addArgument ("8000");
  sop->addArgument ("9000");
  connect (sop, SIGNAL (readyReadStdout ()), this, SLOT (parsestdout ()));
  sop->start ();

}

void
Sopcast::onbuttonplayerclicked ()
{
  killplayer ();
  forkplayer ();
}

void
Sopcast::forkplayer ()
{
  player = new QProcess (this);

  QStringList strlst = QStringList::split (" ", editplayer->text ());
  for (QStringList::Iterator it = strlst.begin (); it != strlst.end (); ++it)
    {
      player->addArgument (*it);
    }

  player->addArgument ("http://localhost:9000");
  player->start ();

}

void
Sopcast::onbuttonstopclicked ()
{
  killsop ();
  killplayer ();
  statusbar->clear ();
}

void
Sopcast::onbuttonquitclicked ()
{
  if (sop)
    sop->kill ();
  if (player)
    player->tryTerminate ();
}

void
Sopcast::killsop ()
{
  if (sop)
    {
      disconnect (sop, SIGNAL (readyReadStdout ()), this,
		  SLOT (parsestdout ()));
//      sop->tryTerminate ();
      sop->kill ();
    }
}

void
Sopcast::killplayer ()
{
  if (player)
    {
      player->tryTerminate ();
//      QTimer::singleShot (500, player, SLOT (kill ()));
    }

}

void
Sopcast::parsestdout ()
{
  QString str, str1, str2;
  str = QString (sop->readStdout ());
//printf("%s",str.ascii());
  if (str.contains ("hook_sc"))
    {
      statusbar->message (tr ("Connected"));
      forkplayer ();
    }
  if (str.contains ("downloadRate") && str.contains ("dnSum"))
    {
      int len = str.find ("dnSum") - str.find ("downloadRate") - 13;
      if (len > 0)
	{
	  str1 = str.mid (str.find ("downloadRate") + 13, len);

	  str2 = str.mid (str.find ("dnSum") + 6, 20);
	  str2 = str2.mid (0, str2.find (QRegExp ("[^0-9]+")));
	  statusbar->message ("R=" + str1 + "S=" + str2 + " " + channelname);

	}
    }
  if (str.contains ("spsc_cleanup"))
    {
      statusbar->message (tr ("sp-sc cleanup"));
    }
}

void
Sopcast::fetchchannel ()
{
  if (fetchingchannel == FALSE)
    {
      fetchingchannel = TRUE;
      buttonchannel->setOn (TRUE);
      listchannel->clear ();

      buffer = new QBuffer ();
      if (!buffer->open (IO_ReadWrite))
	{
	  printf ("cannot create the buffer\n");
	  return;
	}
      QString str = editchannelurl->text ();
      http->setHost (str.section ("/", 2, 2));	//"www.sopcast.org");
      http->get ("/" + str.section ("/", 3), buffer);	//"/channel/index.php", buffer);
    }
  else
    {
      if (!buttonchannel->isOn ())
	buttonchannel->setOn (TRUE);
    }
}

void
Sopcast::httpdone (bool error)
{
  if (buttonchannel->isOn ())
    buttonchannel->setOn (FALSE);
  fetchingchannel = FALSE;

  buffer->reset ();
  QTextStream textstream (buffer);
  textstream.setEncoding (QTextStream::UnicodeUTF8);

  QListViewItem *item;
  QString liststr;
  QString itemstr[8];

  while (textstream.atEnd () == 0)
    {
      liststr = textstream.readLine ();
      if (liststr.contains (editchannelheader->text ()))
	{
	  liststr =
	    liststr.replace ("<a href=", "").replace (">play</a>",
						      "").
	    replace (QRegExp ("<([^<]*)>"), "#").replace (QRegExp ("#( +)#"),
							  "#").replace ("##",
									"#");
	  for (int i = 1; i <= 8; i++)
	    itemstr[i - 1] = liststr.section ("#", i, i).stripWhiteSpace ();

	  item = new QListViewItem (listchannel,
				    itemstr[0], itemstr[1], itemstr[2],
				    itemstr[3], itemstr[4], itemstr[5],
				    itemstr[6], itemstr[7]);
	}
    }
  if (error)
    statusbar->message (tr ("load page error!"));

}

int
Sopcast::sound_read (void)
{
  int result;
  if (ioctl (sound_handle, MIXER_READ (4), &result) == -1)
    {
      perror ("read_error");
      return -1;
    }
  result = ((result >> 8) + (result & 0xFF)) >> 1;
  result = (result > 0) ? result : 0;
  result = (result < 100) ? result : 100;
  return result;
}

void
Sopcast::sound_write (int leftright)
{
  leftright = (leftright < 0) ? 0 : leftright;
  leftright = (leftright > 100) ? 100 : leftright;
  leftright = (leftright << 8) | (leftright & 0xFF);
  if (ioctl (sound_handle, MIXER_WRITE (4), &leftright) == -1)
    {
      perror ("write_error");
      return;
    }
}


int
main (int argc, char **argv)
{
  QApplication a (argc, argv);

  Sopcast w;

  QObject::connect (&a, SIGNAL (aboutToQuit ()), &w,
		    SLOT (onbuttonquitclicked ()));

  w.resize (350, 350);
  a.setMainWidget (&w);
  w.show ();
  return a.exec ();
}

#include "main.moc"
